#include "DBNMetricLearner.h"
#include "FMLKRGeneralizer.h"


DBNMetricLearner::DBNMetricLearner(FMLKRGeneralizer* f)
: SingleVariateMetricLearner(f)
{
	numberOfActions = f->action_number;
	dimension = f->obs_dim;

	reducedDimensions.init(numberOfActions, dimension);


	dependencies.resize(numberOfActions);
	//construct the dependency structure
	for(int i=0; i< numberOfActions; i++)
	{
		MatlabMatrix<int>& mm = dependencies[i];
		mm.init(dimension,dimension);
		for(int j=0; j< dimension; j++)
		{
			reducedDimensions(i,j) = dimension;			//for now everything depends on everything
			for(int k=0; k< dimension; k++)
				mm(j,k) = 1;
		}
	}
	loadDependencies("dependencies.in");
}


// this loads the DBN from the file. the spec of the file is in DBNMetricLearner.h
void DBNMetricLearner::loadDependencies(const char *fname)
{
	//incomplete
	//since I've been playing around with different DBN structures, the code in this method should be carefully checked


	//warning: something for  generalized puddleworld
	for(int i=0; i< numberOfActions; i++)			//for each action
	{
		for(int j=0; j< dimension; j++)
		{
			reducedDimensions(i,j) = 1;		//we only depend on 1 variable
//			reducedDimensions(i,j) = 2;		//this is for 'middle' DBN: adding more dependency as needed
			for(int k=0; k< dimension; k++)
			{
				dependencies[i](j,k) = 0;
			}
			dependencies[i](j,1) = 1;
//			dependencies[i](j,0) = 1;		//this is for 'middle DBN: adding more dependency as needed
		}

	}


/*
	//warning: something for generalized mountain car
	for(int i=0; i< numberOfActions; i++)	//for each action
	{

		for(int j=0; j< dimension; j+=2)
		{
			for(int k=0; k<dimension; k++)
			{
				dependencies[i](j,k) = 0;
				dependencies[i](j+1,k) = 0;
			}
//			reducedDimensions(i,j) = 1;			//x depends on speed only because we use diff learning
			dependencies[i](j,j+1) = 1;			//x doesnt depend on x

//		reducedDimensions(i,j+1) = 1;			//speed depends on x only
//		dependencies[i](j+1,j) = 1;
		//warning: this is for semi wrong DBN. we introduce more dependency between the variables. In this case, the speed is dependent on everything
		reducedDimensions(i,j+1) = 2;			//speed depends on x only
		dependencies[i](j+1,j) = 1;
		dependencies[i](j+1,j+1) = 1;
		}
	}
*/


}


DBNMetricLearner::~DBNMetricLearner(void)
{
}





void DBNMetricLearner::transform(Observation newst, Action a, int dim)
{
	int ind = 0;
	MatlabMatrix<int>& mdep = dependencies[a];
	for(int i=0; i< dimension; i++)
	{
		if (mdep(dim, i)==1)
		{
			newst[ind] = newst[i];
			ind++;
		}
	}

	//set the rest to 0
	for(int i=ind; i< dimension; i++)
		newst[i] = 0;


}

void DBNMetricLearner::transformInMatlab(ANNpointArray& data, int size, Action action, int dim)
{
	ANNpointArray tmp = data;
	data = annAllocPts(size, reducedDimensions(action,dim));
	MatlabMatrix<int>& mdep = dependencies[action];
	for(int i=0; i< size; i++)
	{
		int ind = 0;
		for(int j=0; j< dimension; j++)
		{
			if (mdep(dim, j)==1) //they do depend on each other
			{
				data[i][ind] = tmp[i][j];
				ind++;
			}
		}
	}	//for each data entry

	annDeallocPts(tmp);

}

void DBNMetricLearner::submitAPCChanges(int action, int dim)
{
	//we actually dont do anything here
}


/*
	Here, we are not actually learning the transformation because we have already read it from a DBN.
	However, we have to reallocate data using the DBN dependency graph and return the new dimension
*/

int DBNMetricLearner::learnTransformation(ANNpointArray& data, Observation_type*& targets, int size, int action, int dim)
{
	transformInMatlab(data, size, action, dim);
	return reducedDimensions(action,dim);
}

